home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1994 / MacHack 1994.toast / MacHack™ 1987-1994 / MacHack™ '90 / MacHack'90 Proceedings / John Norstad / Reusable Code / Source / rpp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-10  |  56.9 KB  |  1,970 lines  |  [TEXT/MPS ]

  1. /*______________________________________________________________________
  2.  
  3.     rpp.c - Report Printing Module.
  4.     
  5.     Copyright © 1988, 1989, 1990 Northwestern University.  Permission is 
  6.     granted to use this code in your own projects, provided you give credit 
  7.     to both John Norstad and Northwestern University in your about box or 
  8.     document.
  9.     
  10.     This reusable module implements the printing of reports.
  11.     
  12.     All the code is placed in its own segment named "rpp".
  13. _____________________________________________________________________*/
  14.  
  15.  
  16. #pragma load "precompile"
  17. #include "rpp.h"
  18. #include "utl.h"
  19. #include "doc.h"
  20.  
  21. #pragma segment rpp
  22.  
  23. /*______________________________________________________________________
  24.  
  25.     Globals.
  26. _____________________________________________________________________*/
  27.  
  28.  
  29. static Rect            PrintBox;            /* box enclosing text */
  30. static short        FirstPage;            /* first page number to print */
  31. static short        LastPage;            /* last page number to print */
  32. static Str255        NowDate;                /* current date */
  33. static Str255        NowTime;                /* current time */
  34.  
  35. /* Page break array for type 0 reports.
  36.     
  37.     (**Breaks0)[n] = info for page FirstPage+n,
  38.     for n = 0 through LastPage-FirstPage.
  39.     
  40. */
  41.  
  42. typedef struct Break0Info {
  43.     short                firstLine;            /* line number of first line on page */
  44.     short                numLines;            /* number of lines on page */
  45. } Break0Info;
  46.  
  47. static Break0Info        (**Breaks0)[];        /* handle to page break info */
  48.  
  49. /* Page break array for type 1 reports.
  50.     
  51.     (**Breaks1)[n] = info for page n,
  52.     for n = 1 through the total number of pages in the document.
  53.     
  54.     Note that for type 1 reports we build and keep the entire page break
  55.     array, not just the portion from FirstPage through LastPage.  This is
  56.     because the entire array is needed to print the table of contents.
  57.     
  58. */
  59.  
  60. typedef struct Break1Info {
  61.     short                auxInxB;            /* index in aux array of beginning
  62.                                                 of page */
  63.     short                offsetB;            /* offset in STR# resource of beginning
  64.                                                 of page */
  65.     short                auxInx;            /* index in aux array of first non-blank
  66.                                                 line on page */
  67.     short                offset;            /* offset in STR# resource of first
  68.                                                 non-blank line on page */
  69.     short                hpNum;            /* header page number, or 0 if no
  70.                                                 header on this page */
  71. } Break1Info;
  72.  
  73. static Break1Info        (**Breaks1)[];        /* handle to page break info */
  74.  
  75. /*    Item numbers of items in custom page setup dialog. */
  76.  
  77. #define    sepLineItem        1
  78. #define    fontListItem    2
  79. #define    sizeTEItem        3
  80. #define    sizeListItem    4
  81. #define    reverseItem        5
  82. #define    leftTEItem        6
  83. #define    rightTEItem        7
  84. #define    topTEItem        8
  85. #define    bottomTEItem    9
  86.  
  87. /*    Global variables for custom page setup dialog. */
  88.  
  89. static TPPrDlg             PrtStlDialog;        /* pointer to stream object for page setup */
  90. static TPPrDlg                PrtJobDialog;        /* pointer to stream object for printing */
  91. static short                 FirstItem;            /* our first item number - 1 */
  92. static rpp_PrtBlock        *PBlock;                /* pointer to rpp_PrtBlock param block */
  93. static PItemProcPtr        StdItemProc;        /* pointer to standard item proc */
  94. static ModalFilterProcPtr    StdFltrProc;    /* pointer to standard filter proc */
  95. static ListHandle            FontList;            /* handle to font list */    
  96. static ListHandle            SizeList;            /* handle to size list */
  97.  
  98. /*______________________________________________________________________
  99.  
  100.     GetLSep - Get Line Separation
  101.     
  102.     Entry:    fontNum = font number.
  103.                 fontSize = font size.
  104.     
  105.     Exit:        function result = line speparation.
  106. _____________________________________________________________________*/
  107.  
  108.  
  109. static short GetLSep (short fontNum, short fontSize)
  110.  
  111. {
  112.     FontInfo            fontInfo;        /* font info */
  113.     
  114.     TextFont(fontNum);
  115.     TextSize(fontSize);
  116.     TextFace(normal);
  117.     GetFontInfo(&fontInfo);
  118.     return fontInfo.ascent + fontInfo.descent + fontInfo.leading;
  119. }
  120.  
  121. /*______________________________________________________________________
  122.  
  123.     GetHH - Get Header Height
  124.     
  125.     Entry:    p = pointer to parameter block
  126.     
  127.     Exit:        function result = header height.
  128. _____________________________________________________________________*/
  129.  
  130.  
  131. static short GetHH (rpp_PrtBlock *p)
  132.  
  133. {
  134.     FontInfo            fontInfo;        /* font info */
  135.     
  136.     TextFont(p->titleFont);
  137.     TextSize(p->titleSize);
  138.     TextFace(p->titleStyle);
  139.     GetFontInfo(&fontInfo);
  140.     return fontInfo.ascent + fontInfo.descent + 
  141.         p->titleSep * (**p->hPrint).prInfo.iVRes / 100;
  142. }
  143.  
  144. /*______________________________________________________________________
  145.  
  146.     Break0 - Compute Page Breaks for a Type 0 Report.
  147.     
  148.     Entry:    theList = handle to list record.
  149.                 p = pointer to parameter block.
  150.                 
  151.     Exit:        function result = false (not canceled by command-period).
  152. _____________________________________________________________________*/
  153.  
  154.  
  155. static Boolean Break0 (ListHandle theList, rpp_PrtBlock *p)
  156.  
  157. {
  158.     GrafPtr            port;                /* current grafport */
  159.     short                oldFont;            /* saved font number */
  160.     short                oldFace;            /* saved font style */
  161.     short                oldSize;            /* saved font size */
  162.     short                lineNum;            /* line number of first line on cur page */
  163.     short                lastLine;        /* last line number in report + 1 */
  164.     short                pageNum;            /* current page number */
  165.     short                lineSep;            /* line separation */
  166.     short                height;            /* height of page */
  167.     short                linesPerPage;    /* number of lines per page */
  168.     Break0Info        breakInfo;        /* page break info for current page */
  169.     short                endPage;            /* last page number */
  170.  
  171.     /* Compute linesPerPage = number of report lines per page. */
  172.     
  173.     GetPort(&port);
  174.     oldFont = port->txFont;
  175.     oldFace = port->txFace;
  176.     oldSize = port->txSize;    
  177.     height = PrintBox.bottom - PrintBox.top;    
  178.     if (p->header) height -= GetHH(p);
  179.     lineSep = GetLSep(p->fontNum, p->fontSize);
  180.     linesPerPage = height/lineSep;
  181.     TextFont(oldFont);
  182.     TextFace(oldFace);
  183.     TextSize(oldSize);
  184.     
  185.     /* Compute the PageBreaks array. */
  186.     
  187.     lineNum = (FirstPage-1)*linesPerPage;
  188.     lastLine = (**theList).dataBounds.bottom;
  189.     if (lineNum >= lastLine) {
  190.         LastPage = FirstPage-1;
  191.         Breaks0 = (Break0Info(**)[])NewHandle(0);
  192.     } else {
  193.         endPage = FirstPage + (lastLine-lineNum-1)/linesPerPage;
  194.         if (endPage < LastPage) LastPage = endPage;
  195.         Breaks0 = 
  196.             (Break0Info(**)[])NewHandle(sizeof(Break0Info)*(LastPage-FirstPage+1));
  197.         for (pageNum = FirstPage; pageNum <= LastPage; pageNum++) {
  198.             breakInfo.firstLine = lineNum;
  199.             lineNum += linesPerPage;
  200.             breakInfo.numLines = (lineNum <= lastLine) ? linesPerPage :
  201.                 (lastLine - breakInfo.firstLine);
  202.             (**Breaks0)[pageNum-FirstPage] = breakInfo;
  203.         };
  204.     };
  205.     return false;
  206. };
  207.  
  208. /*______________________________________________________________________
  209.  
  210.     LoadStrings - Load STR# Resource.
  211.     
  212.     Entry:    theList = handle to list record.
  213.                 auxInx = index in aux array.
  214.                 
  215.     Exit:        theStrings = handle to loaded and locked STR# resource.
  216.                 endStrings = pointer to byte following STR# resource.
  217.                 endOfDoc = true if end of STR# resources.
  218. _____________________________________________________________________*/
  219.  
  220.  
  221. static void LoadStrings (ListHandle theList, short auxInx, 
  222.     Handle *theStrings, unsigned char **endStrings, Boolean *endOfDoc)
  223.  
  224. {
  225.     auxInfo            **aux;            /* handle to auxiliary info */
  226.     Handle            s;                    /* handle to STR# resource */
  227.  
  228.     aux = (auxInfo**)(**theList).userHandle;
  229.     if (!(s = (**aux).auxArray[auxInx])) {
  230.         *endOfDoc = true;
  231.         return;
  232.     };
  233.     if (!*s) LoadResource(s);
  234.     MoveHHi(s);
  235.     HLock(s);
  236.     *theStrings = s;
  237.     *endStrings = *s + GetHandleSize(s);
  238. }
  239.  
  240. /*______________________________________________________________________
  241.  
  242.     Wrap - Wrap Paragraph.
  243.     
  244.     Entry:    printing = true to print paragraph, false to just compute
  245.                     paragraph size.
  246.                 v = vertical position on page.
  247.                 fontNum = font number.
  248.                 fontSize = font size.
  249.                 fontStyle = font style.
  250.                 just = justification (docLeft, docCenter, or docRight).
  251.                 theLine = pointer to first line of paragraph.
  252.                 firstChar = pointer to first char of paragraph (following
  253.                     any escape sequences in first line).
  254.     
  255.     Exit:        allBlank = true if paragraph is all blanks.
  256.                 nLines = number of lines in paragraph.
  257.                 lastLine = pointer to last line in paragraph.
  258. _____________________________________________________________________*/
  259.  
  260.  
  261. static void Wrap (Boolean printing, short v, short fontNum, 
  262.     short fontSize, short fontStyle, short just, unsigned char *theLine, 
  263.     unsigned char *firstChar, Boolean *allBlank, short *nLines, 
  264.     unsigned char **lastLine)
  265.  
  266. {
  267.     char                    pl[200];            /* line to be printed */
  268.     short                    npl;                /* length of print line */
  269.     short                    n;                    /* number of lines */
  270.     short                    nbl;                /* num chars in blank run */
  271.     short                    xbl;                /* set to 1 for interpolated blank */
  272.     short                    nw;                /* number of words */
  273.     unsigned char        *q;                /* pointer into cur line */
  274.     unsigned char        *qend;            /* pointer to end+1 of cur line */
  275.     Boolean                eop;                /* true if end of paragraph */
  276.     Boolean                allb;                /* true if all blank paragraph */
  277.     short                    lineSep;            /* line separation */
  278.     FontInfo                fontInfo;        /* font info */
  279.     short                    lineWidth;        /* max width of printed line */
  280.     short                    w;                    /* actual width of printed line */
  281.     
  282.     /* Get font info and set proper font number, size, and style. */
  283.     
  284.     TextFont(fontNum);
  285.     TextSize(fontSize);
  286.     TextFace(normal);
  287.     GetFontInfo(&fontInfo);
  288.     TextFace(fontStyle);
  289.     
  290.     /* Initialize variables. */
  291.     
  292.     n = 1;
  293.     allb = true;
  294.     npl = 0;
  295.     q = firstChar;
  296.     qend = theLine + *theLine + 1;
  297.     eop = false;
  298.     lineWidth = PrintBox.right - PrintBox.left;
  299.     lineSep = fontInfo.leading + fontInfo.ascent + fontInfo.descent;
  300.     if (printing) v += fontInfo.leading + fontInfo.ascent;
  301.     xbl = 0;
  302.     
  303.     /* Main loop.  Wrap the entire paragraph. */
  304.     
  305.     while (!eop) {
  306.     
  307.         /* Check to see if this is the last line in the paragraph.
  308.             If it is, back over the eop marker at the end of the line. */
  309.     
  310.         if (eop = (q < qend && *(qend-1) == docEop)) qend--;
  311.         
  312.         /* Break out blank runs and words from the line one at a time. */
  313.         
  314.         while (q < qend) {
  315.         
  316.             /* Get nbl = num blanks in next blank run. */
  317.             
  318.             nbl = xbl;
  319.             xbl = 0;
  320.             while (q < qend && *q == ' ') {
  321.                 q++;
  322.                 nbl++;
  323.             };
  324.             if (q == qend) break;
  325.             
  326.             /* Get nw = num chars in next word */
  327.             
  328.             allb = false;
  329.             nw = 0;
  330.             while (q < qend && *q != ' ') {
  331.                 q++;
  332.                 nw++;
  333.             };
  334.             
  335.             /* Append blanks and word to current line. */
  336.             
  337.             if (nbl) memset(pl+npl, ' ', nbl);
  338.             npl += nbl;
  339.             memcpy(pl+npl, q-nw, nw);
  340.             npl += nw;
  341.             
  342.             /* Check to see if it's time to wrap.  If it is, print the
  343.                 current line and start a new one.  Put the word we just
  344.                 broke out of the paragraph at the beginning of the next
  345.                 line. */
  346.             
  347.             w = TextWidth(pl, 0, npl);
  348.             if (w > lineWidth) {
  349.                 if (printing) {
  350.                     switch (just) {
  351.                         case docLeft:
  352.                             MoveTo(PrintBox.left, v);
  353.                             break;
  354.                         case docCenter:
  355.                             MoveTo(PrintBox.left + ((lineWidth-w)>>1), v);
  356.                             break;
  357.                         case docRight:
  358.                             MoveTo(PrintBox.right-w, v);
  359.                             break;
  360.                     };
  361.                     DrawText(pl, 0, npl-nw-nbl);
  362.                     v += lineSep;
  363.                 };
  364.                 n++;
  365.                 memcpy(pl, q-nw, nw);
  366.                 npl = nw;
  367.             };
  368.             
  369.         };
  370.         
  371.         /* Break if end of paragraph, else advance to next line.
  372.             Set xbl = 1 to force a blank to be interpolated at the 
  373.             beginning of the next line. */
  374.         
  375.         if (eop) break;
  376.         theLine += *theLine + 1;
  377.         q = theLine + 1;
  378.         qend = q + *theLine;
  379.         xbl = 1;
  380.         
  381.     };
  382.     
  383.     /* Print the last line. */
  384.     
  385.     if (printing) {
  386.         w = TextWidth(pl, 0, npl);
  387.         switch (just) {
  388.             case docLeft:
  389.                 MoveTo(PrintBox.left, v);
  390.                 break;
  391.             case docCenter:
  392.                 MoveTo(PrintBox.left + ((lineWidth-w)>>1), v);
  393.                 break;
  394.             case docRight:
  395.                 MoveTo(PrintBox.right-w, v);
  396.                 break;
  397.         };
  398.         DrawText(pl, 0, npl);
  399.     };
  400.     
  401.     /* Set exit params and return. */
  402.     
  403.     *allBlank = allb;
  404.     *nLines = n;
  405.     *lastLine = theLine;
  406. }
  407.  
  408. /*______________________________________________________________________
  409.  
  410.     CheckCancel - Check for Cancel of Printing Operation.
  411.     
  412.     Exit:            function result = true if canceled, else false.
  413. _____________________________________________________________________*/
  414.  
  415.  
  416. static Boolean CheckCancel(void)
  417.  
  418. {
  419.     EventRecord        myEvent;                /* event record */
  420.     
  421.     if (utl_WaitNextEvent(everyEvent ^ diskMask, &myEvent, 0, nil)) {
  422.         switch (myEvent.what) {
  423.             case keyDown:
  424.                 if ((myEvent.modifiers & cmdKey) &&
  425.                     (myEvent.message & charCodeMask) == '.') return true;
  426.                 break;
  427.             default:
  428.                 break;
  429.         };
  430.     };
  431.     return false;
  432. }
  433.  
  434. /*______________________________________________________________________
  435.  
  436.     Break1 - Compute Page Breaks for a Type 1 Report.
  437.     
  438.     Entry:    theList = handle to list record.
  439.                 p = pointer to parameter block.
  440.                 
  441.     Exit:        Break1 array records positions of page breaks.
  442.                 function result = true if canceled by command-period.
  443. _____________________________________________________________________*/
  444.  
  445.  
  446. static Boolean Break1 (ListHandle theList, rpp_PrtBlock *p)
  447.  
  448. {
  449.     GrafPtr            port;                    /* current grafport */
  450.     short                oldFont;                /* saved font number */
  451.     short                oldFace;                /* saved font style */
  452.     short                oldSize;                /* saved font size */
  453.     short                nalloc;                /* number of elements allocated in
  454.                                                     Breaks1 array */
  455.     Break1Info        breakInfo;            /* break info */                                                    
  456.     short                pageNum;                /* current page number */
  457.     short                hpNum;                /* header page number, or 0 if
  458.                                                     no header on this page */
  459.     short                dirpNum;                /* page number from \page directive,
  460.                                                     or -1 if none specified */
  461.     short                v;                        /* current vert pos on page */
  462.     short                auxInx;                /* cur index in aux array */
  463.     Boolean            allBlank;            /* true if in initial blank portion
  464.                                                     of block */
  465.     Boolean            allBPar;                /* true if all blank paragrah */                                                    
  466.     short                hb;                    /*    height of initial blank portion
  467.                                                     of block */
  468.     short                hnb;                    /* height of non-blank portion of block */
  469.     Boolean            force;                /* true if page break forced by
  470.                                                     \page directive */
  471.     short                lineSep;                /* line separation for normal lines */
  472.     short                h;                        /* height of next section */
  473.     Boolean            endOfDoc;            /* true if end of doc */
  474.     short                headerHeight;        /* height of page header */    
  475.     Handle            theStrings;            /* handle to STR# resource */
  476.     unsigned char    *endStrings;        /* ptr to byte followng STR# rsrc */
  477.     unsigned char    *theLine;            /* pointer to cur line in STR# rsrc */
  478.     unsigned char    *q;                    /* pointer to cur pos in line */
  479.     unsigned char    *qEnd;                /* pointer to end of line */
  480.     Boolean            keepBlock;            /* true if \keep directive encountered */
  481.     Boolean            done;                    /* true when end of section found */
  482.     Boolean            paragraph;            /* true if start of paragraph */
  483.     short                lSep;                    /* size adjusted line separation */
  484.     short                newSize;                /* scaled font size */
  485.     Boolean            pict;                    /* true if picture */
  486.     Handle            hTcon;                /* handle to TCON resource */
  487.     short                nTcon;                /* number of entries in TCON rsrc */
  488.     char                *pTcon;                /* pointer to cur TCON entry */
  489.     short                deltaTcon;            /* height of one printed TCON line */
  490.     short                style;                /* font style */
  491.     short                nLines;                /* num lines in paragraph */
  492.     short                cellHeight;            /* height of list manager cells */
  493.     Boolean            laser;                /* true if laserwriter */
  494.     Boolean            canceled;            /* true if canceled */
  495.     
  496.     /* Save font number, style, and size. */
  497.     
  498.     GetPort(&port);
  499.     oldFont = port->txFont;
  500.     oldFace = port->txFace;
  501.     oldSize = port->txSize;
  502.  
  503.     /* Initialize variables. */
  504.     
  505.     hpNum = pageNum = 0;
  506.     v = PrintBox.bottom + 1;
  507.     auxInx = 0;
  508.     lineSep = GetLSep(p->fontNum, p->fontSize);
  509.     headerHeight = GetHH(p);
  510.     cellHeight = (**theList).cellSize.v;
  511.     endOfDoc = false;
  512.     laser = utl_IsLaser(p->hPrint);
  513.     canceled = false;
  514.     
  515.     /* Load the first STR# resource and lock it. */
  516.     
  517.     LoadStrings(theList, auxInx, &theStrings, &endStrings, &endOfDoc);
  518.     theLine = *theStrings+2;
  519.     
  520.     /* Allocate 10 initial elements in Breaks1 array. */
  521.     
  522.     Breaks1 = (Break1Info(**)[])NewHandle(10*sizeof(Break1Info));
  523.     nalloc = 10;
  524.     
  525.     /* Main loop. Paginate the entire document. */
  526.     
  527.     while (true) {
  528.     
  529.         /* Check for command-period */
  530.         
  531.         if (canceled = CheckCancel()) break;
  532.     
  533.         hb = hnb = 0;
  534.         force = false;
  535.         keepBlock = false;
  536.         breakInfo.auxInxB = breakInfo.auxInx = auxInx;
  537.         breakInfo.offsetB = breakInfo.offset = theLine - *theStrings;
  538.         
  539.         /* Find next "block".  A block is defined to be a possibly empty
  540.             sequence of blank lines, followed by a keep block, a paragraph,
  541.             or a picture.
  542.             
  543.             Our goal is to compute the following:
  544.             
  545.             hb = height of initial blank portion of block.
  546.             hnb = height of non-blank portion of block.
  547.             theLine = pointer to line following block. 
  548.             breakInfo.auxInx = index in aux array of beginning of non-blank
  549.                 portion of block.
  550.             breakInfo.offset = offset in STR# of beginning of non-blank
  551.                 portion of block. */
  552.         
  553.         while (true) {
  554.         
  555.             h = 0;
  556.             allBlank = true;
  557.             done = false;
  558.             
  559.             /* Find next "section".  A section is defined to be an empty
  560.                 line, a keep block, a paragraph, or a picture.
  561.                 
  562.                 Our goal is to compute the following:
  563.                 
  564.                 h = height of section.
  565.                 theLine = pointer to line following section.
  566.                 force = true if \page directive encountered.
  567.                 allBlank = true if blank line. */
  568.             
  569.             while (!done) {
  570.                 
  571.                 lSep = lineSep;
  572.                 q = theLine+1;
  573.                 qEnd = q + *theLine;
  574.                 paragraph = true;
  575.                 pict = false;
  576.                 style = normal;
  577.                 newSize = p->fontSize;
  578.                 
  579.                 /* Crack escape sequences. */
  580.                 
  581.                 while (q < qEnd && *q < 31) {
  582.                     switch (*q) {
  583.                         case docStyle:
  584.                             style = *(q+2);
  585.                             break;
  586.                         case docSize:
  587.                             newSize = utl_ScaleFontSize(p->fontNum, p->fontSize,
  588.                                 *(q+2)<<8 | *(q+3), laser);
  589.                             lSep = GetLSep(p->fontNum, newSize);
  590.                             break;
  591.                         case docOnly:
  592.                             paragraph = *(q+2) & docPrint;
  593.                             break;
  594.                         case docPict:
  595.                             pict = true;
  596.                             paragraph = false;
  597.                             break;
  598.                         case docPage:
  599.                             force = true;
  600.                             dirpNum = *(q+2)<<8 | *(q+3);
  601.                             if (dirpNum == -1) {
  602.                                 if (hpNum) hpNum++;
  603.                             } else if (!dirpNum) {
  604.                                 hpNum = 0;
  605.                             } else {
  606.                                 hpNum = dirpNum;
  607.                             };
  608.                             paragraph = false;
  609.                             break;
  610.                         case docKeep:
  611.                             keepBlock = true;
  612.                             paragraph = false;
  613.                             break;
  614.                         case docEndKeep:
  615.                             done = true;
  616.                             paragraph = false;
  617.                             break;
  618.                         case docITcon:
  619.                             hTcon = GetResource('TCON', p->tabConID);
  620.                             if (!*hTcon) LoadResource(hTcon);
  621.                             nTcon = **(short**)hTcon;
  622.                             pTcon = *hTcon+4;
  623.                             deltaTcon = lineSep + (*(q+2)<<8 | *(q+3)) *
  624.                                 (**p->hPrint).prInfo.iVRes / 100;
  625.                             while (nTcon--) {
  626.                                 if (*pTcon & docPrint) h += deltaTcon;
  627.                                 pTcon += *(pTcon+1) + 4;
  628.                                 if ((long)pTcon & 1) pTcon++;
  629.                             };
  630.                             allBlank = false;
  631.                             done = true;
  632.                             paragraph = false;
  633.                             break;
  634.                     };
  635.                     if (!paragraph) break;
  636.                     q += *(q+1);
  637.                 };
  638.                 
  639.                 /* Rewrap paragraph. */
  640.                 
  641.                 if (paragraph) {
  642.                     Wrap(false, 0, p->fontNum, newSize, style, docLeft, theLine,
  643.                         q, &allBPar, &nLines, &theLine);
  644.                     allBlank &= allBPar;
  645.                     h += nLines * lSep;
  646.                     done = !keepBlock;
  647.                 };
  648.                 
  649.                 if (pict) {
  650.                 
  651.                     /* For a picture, count the bands and compute h = the picture
  652.                         height. */
  653.                         
  654.                     while (true) {
  655.                         h += cellHeight;
  656.                         theLine += *theLine + 1;
  657.                         q = theLine + 1;
  658.                         qEnd = q + *theLine;
  659.                         pict = false;
  660.                         while (q < qEnd && *q < 31) {
  661.                             if (*q == docPict) {
  662.                                 pict = true;
  663.                                 break;
  664.                             };
  665.                             q += *(q+1);
  666.                         };
  667.                         if (!pict) break;
  668.                     };
  669.                     allBlank = false;
  670.                     done = !keepBlock;
  671.                     
  672.                 } else {
  673.                 
  674.                     /* If not a picture, advance to next line. */
  675.                 
  676.                     theLine += *theLine + 1;
  677.                     
  678.                 };
  679.                 
  680.                 /* Advance to next STR# resource if necessary. */
  681.                 
  682.                 if (theLine >= endStrings) {
  683.                     HUnlock(theStrings);
  684.                     auxInx++;
  685.                     LoadStrings(theList, auxInx, &theStrings, &endStrings, 
  686.                         &endOfDoc);
  687.                     if (endOfDoc) break;
  688.                     theLine = *theStrings + 2;
  689.                 };
  690.                 
  691.             };
  692.             
  693.             /* At this point we have found the next section, and h = the
  694.                 height of the section. */
  695.             
  696.             if (allBlank) {
  697.             
  698.                 /* Accumulate height of blank line and loop for next section. */
  699.             
  700.                 hb += h;
  701.                 breakInfo.auxInx = auxInx;
  702.                 breakInfo.offset = theLine - *theStrings;
  703.                 if (endOfDoc) break;
  704.                 
  705.             } else {
  706.             
  707.                 /* Not blank line - set height of keep block, picture, or
  708.                     paragraph and break out of the section loop. */
  709.             
  710.                 hnb = h;
  711.                 break;
  712.                 
  713.             };
  714.             
  715.         };
  716.         
  717.         /* At this point we have found the next block, and we have: 
  718.             hb = height of blank portion at beginning of block.
  719.             hnb = height of non-blank portion (keep block, pict, or paragraph).
  720.         
  721.             Check to see if there's enough room on the page for this block. */
  722.         
  723.         if (v+hb+hnb > PrintBox.bottom || force) {
  724.             
  725.             /* Not enough room for block or \page encountered - do a page break.  
  726.                 Don't put blank lines at the top of the page. */
  727.         
  728.             pageNum++;
  729.             if (!force && hpNum) hpNum++;
  730.             breakInfo.hpNum = hpNum;
  731.             if (pageNum >= nalloc) {
  732.                 SetHandleSize((Handle)Breaks1, 
  733.                     GetHandleSize((Handle)Breaks1) + 10*sizeof(Break1Info));
  734.                 nalloc += 10;
  735.             };
  736.             (**Breaks1)[pageNum] = breakInfo;
  737.             v = PrintBox.top;
  738.             if (hpNum) v += headerHeight;
  739.             v += hnb;
  740.             
  741.         } else {
  742.         
  743.             /* Enough room for block - advance position on page. */
  744.         
  745.             v += hb + hnb;
  746.             
  747.         };
  748.         
  749.         if (endOfDoc) break;
  750.         
  751.     };
  752.     
  753.     /* Set LastPage and adjust final size of Break1 array. */
  754.     
  755.     if (pageNum < LastPage) LastPage = pageNum;
  756.     if (LastPage < FirstPage) LastPage = FirstPage-1;
  757.     SetHandleSize((Handle)Breaks1, (pageNum+1)*sizeof(Break1Info));
  758.     
  759.     /* Restore font number, style, and size. */
  760.     
  761.     TextFont(oldFont);
  762.     TextFace(oldFace);
  763.     TextSize(oldSize);
  764.     
  765.     return canceled;
  766. }
  767.  
  768. /*______________________________________________________________________
  769.  
  770.     PrintHeader - Print Page Header.
  771.     
  772.     Entry:    p = pointer to parameter block.
  773.                 pageNum = page number to print.
  774. _____________________________________________________________________*/
  775.  
  776.  
  777. static void PrintHeader (rpp_PrtBlock *p, short pageNum)
  778.  
  779. {
  780.     FontInfo        fontInfo;            /* font info */
  781.     short            v;                        /* vert coord of header base line */
  782.     Str255        pNum;                    /* page number */
  783.     Str255        rhSide;                /* date, time, and page number */
  784.     
  785.     TextFont(p->titleFont);
  786.     TextSize(p->titleSize);
  787.     TextFace(p->titleStyle);
  788.     GetFontInfo(&fontInfo);
  789.     v = PrintBox.top + fontInfo.ascent;
  790.     MoveTo(PrintBox.left, v);
  791.     DrawString(p->title);
  792.     NumToString(pageNum, pNum);
  793.     utl_PlugParams(p->titleTmpl, rhSide, NowDate, NowTime, pNum, nil);
  794.     MoveTo(PrintBox.right - StringWidth(rhSide), v);
  795.     DrawString(rhSide);
  796. }
  797.  
  798. /*______________________________________________________________________
  799.  
  800.     Print0 - Print one Page from a Type 0 Report.
  801.     
  802.     Entry:    theList = handle to list record.
  803.                 p = pointer to parameter block.
  804.                 pageNum = page number to print.
  805. _____________________________________________________________________*/
  806.  
  807.  
  808. static void Print0 (ListHandle theList, rpp_PrtBlock *p, short pageNum)
  809.  
  810. {
  811.     short                v;                /* current vertical coord on page */
  812.     FontInfo            fontInfo;    /* font info */
  813.     short                lineSep;        /* line separation */
  814.     Cell                theCell;        /* list manager cell */
  815.     char                line[256];    /* line to be printed */
  816.     short                lineLen;        /* length of line */
  817.     Break0Info        breakInfo;    /* page break info */
  818.  
  819.     v = PrintBox.top;
  820.     
  821.     /* Print the page header, if requested. */
  822.     
  823.     if (p->header) {
  824.         PrintHeader(p, pageNum);
  825.         v += GetHH(p);
  826.     };
  827.     if (CheckCancel()) return;
  828.     
  829.     /* Print the page body. */
  830.     
  831.     TextFont(p->fontNum);
  832.     TextSize(p->fontSize);
  833.     TextFace(normal);
  834.     GetFontInfo(&fontInfo);
  835.     lineSep = fontInfo.ascent + fontInfo.descent + fontInfo.leading;
  836.     breakInfo = (**Breaks0)[pageNum-FirstPage];
  837.     SetPt(&theCell, 0, breakInfo.firstLine);
  838.     while (breakInfo.numLines--) {
  839.         if (CheckCancel()) return;
  840.         v += lineSep;
  841.         lineLen = 256;
  842.         LGetCell(line, &lineLen, theCell, theList);
  843.         MoveTo(PrintBox.left, v);
  844.         DrawText(&line, 0, lineLen);
  845.         theCell.v++;
  846.     };
  847.     return;
  848. }
  849.  
  850. /*______________________________________________________________________
  851.  
  852.     Print1 - Print one Page from a Type 1 Report..
  853.     
  854.     Entry:    theList = handle to list record.
  855.                 p = pointer to parameter block.
  856.                 pageNum = page number to print.
  857. _____________________________________________________________________*/
  858.  
  859.  
  860. static void Print1 (ListHandle theList, rpp_PrtBlock *p, short pageNum)
  861.  
  862. {
  863.     short                v;                    /* current vertical coord on page */
  864.     Break1Info        breakInfo;        /* page break info */
  865.     short                auxInx;            /* cur index in aux array */
  866.     short                offset;            /* cur offset in aux array */
  867.     short                endAuxInx;        /* ending index in aux array */
  868.     short                endOffset;        /* ending offset in STR# rsrc */
  869.     FontInfo            fontInfo;        /* font info */
  870.     short                lineSep;            /* line separation */
  871.     Handle            theStrings;        /* handle to STR# rsrc */
  872.     unsigned char    *endStrings;    /* ptr to byte following STR# rsrc */
  873.     unsigned char    *theLine;        /* ptr to cur line in STR# rsrc */
  874.     unsigned char    *q;                /* ptr to cur pos in line */
  875.     unsigned char    *qEnd;            /* ptr to end of line */
  876.     Boolean            endOfDoc;        /* true if end of doc */
  877.     Boolean            endOfPage;        /* true if end of page */
  878.     Boolean            allBlank;        /* true if all blank paragraph (not used) */
  879.     Boolean            paragraph;        /* true if start of paragraph */
  880.     Boolean            pict;                /* true if start of picture */
  881.     short                lSep;                /* size adjusted line separation */
  882.     short                newSize;            /* scaled font size */
  883.     short                style;            /* font style */
  884.     short                escJust;            /* true if just escape sequence */
  885.     short                just;                /* justification */
  886.     short                nLines;            /* num lines in paragraph */
  887.     short                nBands;            /* num bands in picture */
  888.     short                picID;            /* resource id of picture */
  889.     PicHandle        picHandle;        /* handle to picture */
  890.     Rect                picRect;            /* picture dest rect */
  891.     short                picLeft;            /* left coord of picture */
  892.     short                tconMaxT;        /* width of widest tcon title */
  893.     short                tconMaxN;        /* width of widest tcon page number */
  894.     short                tconXSpace;        /* extra space between lines */
  895.     short                tconLSep;        /* tcon line separation */
  896.     short                tconLeft;        /* left margin for tcon */
  897.     short                tconRight;        /* right margin for tcon */
  898.     char                *tconPtr;        /* ptr to cur pos in TCON rsrc */
  899.     short                tconCount;        /* num TCON entries left to process */
  900.     Handle            tconHandle;        /* handle to TCON rsrc */
  901.     Break1Info        *tconBPtr;        /* ptr to cur pos in Breaks1 array */
  902.     Break1Info        *tconBEnd;        /* ptr to end of Breaks1 array */
  903.     short                tconPass;        /* pass number - 0 or 1 */
  904.     short                tconLine;        /* line number */
  905.     unsigned char    *tconData;        /* pointer to cell data */
  906.     short                tconAuxInx;        /* index in aux array */
  907.     short                tconOffset;        /* offset in STR# resource */
  908.     short                tconPageNum;    /* page number */
  909.     Str255            tconPNum;        /* page number as a string */
  910.     short                tconTWidth;        /* width of title */
  911.     short                tconNWidth;        /* width of page number */
  912.     short                tconHPeriod;    /* hor coord of dot */
  913.     short                tconPerSep;        /* tcon dot separation */
  914.     unsigned char    *tconStart;        /* ptr to first non-blank char of tcon
  915.                                                 title */
  916.     short                tconNBl;            /* number of leading blanks in tcon
  917.                                                 title */
  918.     Boolean            laser;            /* true if laserwriter */                                                
  919.  
  920.     v = PrintBox.top;
  921.     laser = utl_IsLaser(p->hPrint);
  922.     
  923.     /* Get page break info for this page. */
  924.     
  925.     breakInfo = (**Breaks1)[pageNum];
  926.     auxInx = breakInfo.auxInx;
  927.     offset = breakInfo.offset;
  928.     
  929.     /* Get info about where this page ends:
  930.         endAuxInx = index in aux array where page ends.
  931.         endOffset = offset in STR# rsrc where page ends. */
  932.         
  933.     if ((pageNum+1)*sizeof(Break1Info) < GetHandleSize((Handle)Breaks1)) {
  934.         endAuxInx = (**Breaks1)[pageNum+1].auxInx;
  935.         endOffset = (**Breaks1)[pageNum+1].offset;
  936.     } else {
  937.         endAuxInx = endOffset = 0x7fff;
  938.     };
  939.     
  940.     /* Print the page header, if any. */
  941.     
  942.     if (breakInfo.hpNum && p->header) {
  943.         PrintHeader(p, breakInfo.hpNum);
  944.         v += GetHH(p);
  945.     };
  946.     if (CheckCancel()) return;
  947.     
  948.     /* Set the font number, size, and style, and get font info. */
  949.     
  950.     TextFont(p->fontNum);
  951.     TextSize(p->fontSize);
  952.     TextFace(normal);
  953.     GetFontInfo(&fontInfo);
  954.     lineSep = fontInfo.ascent + fontInfo.descent + fontInfo.leading;
  955.     
  956.     /* Load the first STR# resource and lock it.  Initialize theLine
  957.         to point to the first line to be printed. */
  958.     
  959.     endOfDoc = false;
  960.     LoadStrings(theList, auxInx, &theStrings, &endStrings, &endOfDoc);
  961.     theLine = *theStrings + offset;
  962.     
  963.     /* Initialize other variables. */
  964.     
  965.     endOfPage = endOfDoc;
  966.     
  967.     /* Main loop.  Print the page. */
  968.     
  969.     while (!endOfPage) {
  970.     
  971.         if (CheckCancel()) break;
  972.         lSep = lineSep;
  973.         q = theLine+1;
  974.         qEnd = q + *theLine;
  975.         paragraph = true;
  976.         pict = false;
  977.         style = normal;
  978.         newSize = p->fontSize;
  979.         escJust = false;
  980.         
  981.         /* Crack escape sequences. */
  982.         
  983.         while (q < qEnd && *q < 31) {
  984.             switch (*q) {
  985.                 case docStyle:
  986.                     style = *(q+2);
  987.                     break;
  988.                 case docSize:
  989.                     newSize = utl_ScaleFontSize(p->fontNum, p->fontSize,
  990.                         *(q+2)<<8 | *(q+3), laser);
  991.                     lSep = GetLSep(p->fontNum, newSize);
  992.                     break;
  993.                 case docJust:
  994.                     escJust = true;
  995.                     just = *(q+2);
  996.                     break;
  997.                 case docOnly:
  998.                     paragraph = *(q+2) & docPrint;
  999.                     break;
  1000.                 case docPict:
  1001.                     pict = true;
  1002.                     picID = *(q+2)<<8 | *(q+3);
  1003.                     paragraph = false;
  1004.                     break;
  1005.                 case docPage:
  1006.                 case docKeep:
  1007.                 case docEndKeep:
  1008.                     paragraph = false;
  1009.                     break;
  1010.                 case docITcon:
  1011.                     tconXSpace = *(q+2)<<8 | *(q+3);
  1012.                     tconLSep = lineSep + 
  1013.                         tconXSpace * (**p->hPrint).prInfo.iVRes / 100;
  1014.                     tconMaxT = tconMaxN = 0;
  1015.                     TextFont(p->fontNum);
  1016.                     TextSize(p->fontSize);
  1017.                     TextFace(normal);
  1018.                     tconHandle = GetResource('TCON', p->tabConID);
  1019.                     if (!*tconHandle) LoadResource(tconHandle);
  1020.                     MoveHHi(tconHandle);
  1021.                     HLock(tconHandle);
  1022.                     for (tconPass = 0; tconPass < 2; tconPass++) {
  1023.                         tconCount = **(short**)tconHandle;
  1024.                         tconPtr = *tconHandle+2;
  1025.                         while (tconCount--) {
  1026.                             if (CheckCancel()) return;
  1027.                             if (*(tconPtr+2) & docPrint) {
  1028.                                 tconLine = *(short*)tconPtr;
  1029.                                 tconData = *(**theList).cells + 
  1030.                                     (**theList).cellArray[tconLine];
  1031.                                 tconAuxInx = *tconData;
  1032.                                 tconOffset = *(tconData+1)<<8 | *(tconData+2);
  1033.                                 tconBPtr = (Break1Info*)*Breaks1;
  1034.                                 tconBEnd = (Break1Info*)((char*)tconBPtr + 
  1035.                                     GetHandleSize((Handle)Breaks1));
  1036.                                 tconBPtr++;
  1037.                                 while (tconBPtr < tconBEnd) {
  1038.                                     if (tconAuxInx < tconBPtr->auxInxB) break;
  1039.                                     if (tconAuxInx == tconBPtr->auxInxB &&
  1040.                                         tconOffset < tconBPtr->offsetB) break;
  1041.                                     tconBPtr++;
  1042.                                 };
  1043.                                 tconBPtr--;
  1044.                                 tconPageNum = tconBPtr->hpNum;
  1045.                                 tconStart = tconPtr+4;
  1046.                                 while (*tconStart == ' ') tconStart++;
  1047.                                 tconNBl = tconStart - tconPtr - 4;
  1048.                                 tconTWidth = ((tconNBl*p->fontSize)>>1) +
  1049.                                     TextWidth(tconStart, 0, *(tconPtr+3)-tconNBl);
  1050.                                 NumToString(tconPageNum, tconPNum);
  1051.                                 tconNWidth = StringWidth(tconPNum);
  1052.                                 if (!tconPass) {
  1053.                                     if (tconTWidth > tconMaxT) tconMaxT = tconTWidth;
  1054.                                     if (tconNWidth > tconMaxN) tconMaxN = tconNWidth;
  1055.                                 } else {
  1056.                                     v += tconLSep;
  1057.                                     MoveTo(tconLeft + ((tconNBl*p->fontSize)>>1), v);
  1058.                                     DrawText(tconStart, 0, *(tconPtr+3)-tconNBl);
  1059.                                     MoveTo(tconRight-tconNWidth, v);
  1060.                                     DrawString(tconPNum);
  1061.                                     tconPerSep = (p->fontSize - 4) >> 1;
  1062.                                     if (tconPerSep < 3) tconPerSep = 3;
  1063.                                     tconHPeriod = tconRight-tconMaxN-(tconPerSep<<1);
  1064.                                     while (tconHPeriod > tconLeft+tconTWidth+tconPerSep) {
  1065.                                         MoveTo(tconHPeriod, v);
  1066.                                         DrawChar('.');
  1067.                                         tconHPeriod -= tconPerSep;
  1068.                                     };
  1069.                                 };
  1070.                             };
  1071.                             tconPtr += *(tconPtr+3) + 4;
  1072.                             if ((long)tconPtr & 1) tconPtr++;
  1073.                         };
  1074.                         if (!tconPass) {
  1075.                             tconLeft = PrintBox.left + 
  1076.                                 (((PrintBox.right-PrintBox.left) -
  1077.                                 (tconMaxT+tconMaxN+72))>>1);
  1078.                             tconRight = tconLeft + tconMaxT + tconMaxN + 72;
  1079.                         };
  1080.                     };
  1081.                     HUnlock(tconHandle);                    
  1082.                     paragraph = false;
  1083.                     break;
  1084.             };
  1085.             if (!paragraph) break;
  1086.             q += *(q+1);
  1087.         };
  1088.         
  1089.         /* Rewrap paragraph. */
  1090.         
  1091.         if (paragraph) {
  1092.             if (!escJust) just = docLeft;
  1093.             Wrap(true, v, p->fontNum, newSize, style, just, theLine,
  1094.                 q, &allBlank, &nLines, &theLine);
  1095.             v += nLines * lSep;
  1096.         };
  1097.         
  1098.         if (pict) {
  1099.         
  1100.             /* Draw picture. */
  1101.         
  1102.             nBands = 0;
  1103.             while (true) {
  1104.                 nBands++;
  1105.                 theLine += *theLine + 1;
  1106.                 q = theLine + 1;
  1107.                 qEnd = q + *theLine;
  1108.                 pict = false;
  1109.                 while (q < qEnd && *q < 31) {
  1110.                     if (*q == docPict) {
  1111.                         pict = true;
  1112.                         break;
  1113.                     };
  1114.                     q += *(q+1);
  1115.                 };
  1116.                 if (!pict) break;
  1117.             };
  1118.             picHandle = GetPicture(picID);
  1119.             picRect = (**picHandle).picFrame;
  1120.             if (!escJust) just = docCenter;
  1121.             switch (just) {
  1122.                 case docLeft:
  1123.                     picLeft = PrintBox.left;
  1124.                     break;
  1125.                 case docCenter:
  1126.                     picLeft = PrintBox.left + (((PrintBox.right-PrintBox.left) -
  1127.                         (picRect.right-picRect.left))>>1);
  1128.                     break;
  1129.                 case docRight:
  1130.                     picLeft = PrintBox.right - (picRect.right-picRect.left);
  1131.                     break;
  1132.             };
  1133.             OffsetRect(&picRect, picLeft-picRect.left, v-picRect.top);
  1134.             HLock((Handle)picHandle);
  1135.             DrawPicture(picHandle, &picRect);
  1136.             HUnlock((Handle)picHandle);
  1137.             v += nBands * (**theList).cellSize.v;
  1138.                     
  1139.         } else {
  1140.         
  1141.             /* If not a picture, advance to next line. */
  1142.         
  1143.             theLine += *theLine + 1;
  1144.             
  1145.         };
  1146.         
  1147.         /* Advance to next STR# resource if necessary. */
  1148.         
  1149.         if (theLine >= endStrings) {
  1150.             HUnlock(theStrings);
  1151.             auxInx++;
  1152.             LoadStrings(theList, auxInx, &theStrings, &endStrings, 
  1153.                 &endOfDoc);
  1154.             if (endOfDoc) break;
  1155.             theLine = *theStrings + 2;
  1156.         };
  1157.         
  1158.         /* Check for end of page. */
  1159.         
  1160.         endOfPage = auxInx >= endAuxInx && 
  1161.             (theLine - *theStrings) >= endOffset;
  1162.         
  1163.     };
  1164. }
  1165.  
  1166. /*______________________________________________________________________
  1167.  
  1168.     CalcPrintBox - Calculate Printing Rectangle
  1169.     
  1170.     Entry:    hPrint = handle to print record.
  1171.                 leftMargin = left margin in 1/100 inch.
  1172.                 rightMargin = right margin in 1/100 inch.
  1173.                 topMargin = top margin in 1/100 inch.
  1174.                 botMargin = bot margin in 1/100 inch.
  1175.                 
  1176.     Exit:        global variable PrintBox = printing rectangle.
  1177. _____________________________________________________________________*/
  1178.  
  1179.  
  1180. static void CalcPrintBox (THPrint hPrint, short leftMargin, 
  1181.     short rightMargin, short topMargin, short botMargin)
  1182.  
  1183. {
  1184.     Rect                rPaper;                /* paper rect */
  1185.     Rect                rPage;                /* page rect */
  1186.     short                iVRes;                /* vert printer resolution */
  1187.     short                iHRes;                /* horiz printer resolution */
  1188.     
  1189.     rPaper = (**hPrint).rPaper;
  1190.     rPage = (**hPrint).prInfo.rPage;
  1191.     iVRes = (**hPrint).prInfo.iVRes;
  1192.     iHRes = (**hPrint).prInfo.iHRes;
  1193.     PrintBox.left = rPaper.left + leftMargin*iHRes/100;
  1194.     if (PrintBox.left < 0) PrintBox.left = 0;
  1195.     PrintBox.right = rPaper.right - rightMargin*iHRes/100;
  1196.     if (PrintBox.right > rPage.right) PrintBox.right = rPage.right;
  1197.     PrintBox.top = rPaper.top + topMargin*iVRes/100;
  1198.     if (PrintBox.top < 0) PrintBox.top = 0;
  1199.     PrintBox.bottom = rPaper.bottom - botMargin*iVRes/100;
  1200.     if (PrintBox.bottom > rPage.bottom) PrintBox.bottom = rPage.bottom;
  1201. }
  1202.  
  1203. /*______________________________________________________________________
  1204.  
  1205.     MyJobDlgInit - Initialize custom printing dialog.
  1206.     
  1207.     Entry:    hPrint = handle to print record.
  1208.     
  1209.     Exit:        function result = pointer to print dialog stream object.
  1210. _____________________________________________________________________*/
  1211.  
  1212.  
  1213. static pascal TPPrDlg MyJobDlgInit (THPrint hPrint)
  1214.  
  1215. {
  1216. #pragma unused (hPrint)
  1217.  
  1218.     DialogPtr        theDialog;        /* pointer to dialog */
  1219.     Rect                dlogRect;        /* dialog rectangle */
  1220.     
  1221.     theDialog = (DialogPtr)PrtJobDialog;
  1222.     
  1223.     /* Center the dialog. */
  1224.     
  1225.     dlogRect = theDialog->portRect;
  1226.     utl_CenterDlogRect(&dlogRect, PBlock->menuPick);
  1227.     MoveWindow(theDialog, dlogRect.left, dlogRect.top, false);
  1228.     
  1229.     return PrtJobDialog;
  1230. };
  1231.  
  1232. /*______________________________________________________________________
  1233.  
  1234.     rpp_Print - Print a Report.
  1235.     
  1236.     Entry:    repHandle = handle to report record.
  1237.                 printOne = true to bypass print job dialog.
  1238.                 p = pointer to parameter block, with fields set as follows:
  1239.     
  1240.                 hPrint = handle to print record.
  1241.                 fontNum = font number.
  1242.                 fontSize = font size.
  1243.                 topMargin = top page margin, in 1/100 inch.
  1244.                 botMargin = bottom page margin, in 1/100 inch.
  1245.                 leftMargin = left page margin, in 1/100 inch.
  1246.                 rightMargin = right page margin, in 1/100 inch.
  1247.                 reverseOrder = true to print pages in reverse order.
  1248.                 header = true to print page headers.
  1249.                 title = ptr to header title.  If header=true it this
  1250.                     string is printed at the top of each page left-justified.
  1251.                 titleSep = vertical separation between page header and 
  1252.                     first line of text, in 1/100 inch.
  1253.                 titleFont = font number for headers.
  1254.                 titleStyle = font style for headers.
  1255.                 titleSize = font size for headers.
  1256.                 titleTmpl = ptr to template for header date, time, and page number.
  1257.                     e.g., "^0  ^1  page ^2".  The place-holders ^0, ^1, and ^2
  1258.                     are replaced by the current date, time, and page number.
  1259.                     This string is drawn right-justified at the top of each page,
  1260.                     if header=true.
  1261.                 docName = ptr to document name for printing in progress
  1262.                     dialog.
  1263.                 dlogID = resource id of printing dialog.  The place-holder
  1264.                     ^0 is replaced by the document name.
  1265.                 tabConID = TCON resource id, for type 1 reports only.
  1266.                 emptyPageRangeID = no pages in page range alert.
  1267.                 menuPick = true if Print command was via menu pick, 
  1268.                     false if command key used.
  1269.                 updateAll = pointer to function to handle all pending update
  1270.                     events, or nil if none. The function is called after the
  1271.                     job dialog is dismissed, and before the printing in progress
  1272.                     dialog is presented.
  1273.                     
  1274.     Exit:        function result = error code.
  1275.     
  1276.     The caller must allocate and initialize a print record, and call 
  1277.     PrStlDialog to present the page setup dialog and initialize the print
  1278.     record.  rep_Print calls PrJobDialog to present the job dialog.
  1279.     The printing manager should be closed before calling rep_Print.
  1280. _____________________________________________________________________*/
  1281.  
  1282.  
  1283. OSErr rpp_Print (Handle repHandle, Boolean printOne, rpp_PrtBlock *p)
  1284.  
  1285. {
  1286.     ListHandle        theList;                /* handle to list record */
  1287.     OSErr                rCode;                /* print manager error code */
  1288.     Boolean            printOK;                /* true if user said OK in job dialog */
  1289.     GrafPtr            savedPort;            /* saved grafport */
  1290.     short                savedResFile;        /* saved cur res file */
  1291.     short                printingResFile;    /* printing res file */
  1292.     TPPrPort            port;                    /* printing port */
  1293.     TPrStatus        prStatus;            /* printer status record */
  1294.     short                pageNum;                /* current page number */
  1295.     unsigned long    secs;                    /* current time */
  1296.     CursHandle        watch;                /* handle to watch cursor */
  1297.     DialogPtr        dlog;                    /* pointer to printing dialog */
  1298.     short                nCopies;                /* number of copies */
  1299.     Boolean            laser;                /* true if laserwriter */
  1300.     short                first;                /* first page number */
  1301.     short                last;                    /* last page number */
  1302.     Str255            firstStr;            /* first page number */
  1303.     Str255            lastStr;                /* last page number */
  1304.     Boolean            canceled;            /* true if canceled by Cmd-Period */
  1305.     Rect                dlogRect;            /* printing in progress dialog rectangle */
  1306.     
  1307.     PBlock = p;
  1308.     theList = (ListHandle)repHandle;
  1309.     GetPort(&savedPort);
  1310.     savedResFile = CurResFile();
  1311.     
  1312.     /* Get current date and time for headers. */
  1313.     
  1314.     if (p->header) {
  1315.         GetDateTime(&secs);
  1316.         IUDateString(secs, shortDate, &NowDate);
  1317.         IUTimeString(secs, true, &NowTime);
  1318.     };
  1319.     
  1320.     CalcPrintBox(p->hPrint, p->leftMargin, p->rightMargin, p->topMargin,
  1321.         p->botMargin);
  1322.     
  1323.     if (!(rCode = PrError())) {
  1324.     
  1325.         /* Put up the standard job dialog */
  1326.  
  1327.         if (!printOne) {
  1328.             PrtJobDialog = PrJobInit(p->hPrint);
  1329.             printOK = PrDlgMain(p->hPrint, MyJobDlgInit);
  1330.             rCode = PrError();
  1331.             if (PBlock->updateAll) (*PBlock->updateAll)();
  1332.         } else {
  1333.             printOK = true;
  1334.             (**p->hPrint).prJob.iFstPage = 1;
  1335.             (**p->hPrint).prJob.iLstPage = 999;
  1336.         };
  1337.     
  1338.         /* Print the report. */
  1339.         
  1340.         if (!rCode && printOK) {
  1341.             watch = GetCursor(watchCursor);
  1342.             SetCursor(*watch);
  1343.             printingResFile = CurResFile();
  1344.             UseResFile(savedResFile);
  1345.             UseResFile(printingResFile);
  1346.             dlog = GetNewDialog(p->dlogID, nil, (WindowPtr)-1);
  1347.             dlogRect = dlog->portRect;
  1348.             utl_CenterDlogRect(&dlogRect, p->menuPick);
  1349.             MoveWindow(dlog, dlogRect.left, dlogRect.top, false);
  1350.             SetWTitle((WindowPtr)dlog, p->docName);
  1351.             ParamText(p->docName, nil, nil, nil);
  1352.             ShowWindow((WindowPtr)dlog);
  1353.             DrawDialog(dlog);
  1354.             first = FirstPage = (**p->hPrint).prJob.iFstPage;
  1355.             last = LastPage = (**p->hPrint).prJob.iLstPage;
  1356.             if (FirstPage <= 1) FirstPage = 1;
  1357.             if (LastPage > 999) LastPage = 999;
  1358.             (**p->hPrint).prJob.iFstPage = 1;
  1359.             (**p->hPrint).prJob.iLstPage = 999;
  1360.             if ((**theList).refCon) {
  1361.                 canceled = Break1(theList, p);
  1362.             } else {
  1363.                 canceled = Break0(theList, p);
  1364.             };
  1365.             if (!canceled) {
  1366.                 if (FirstPage > LastPage) {
  1367.                     NumToString(first, firstStr);
  1368.                     NumToString(last, lastStr);
  1369.                     ParamText(firstStr, lastStr, nil, nil);
  1370.                     utl_StopAlert(p->emptyPageRangeID, nil, 0);
  1371.                 } else {
  1372.                     laser = utl_IsLaser(p->hPrint);
  1373.                     nCopies = ((**p->hPrint).prJob.bJDocLoop == bDraftLoop && 
  1374.                         !laser) ? (**p->hPrint).prJob.iCopies : 1;
  1375.                     PrValidate(p->hPrint);        /* set doc title - see TN 149 */
  1376.                     while (nCopies--) {
  1377.                         port = PrOpenDoc(p->hPrint, nil, nil);
  1378.                         pageNum = p->reverseOrder ? LastPage : FirstPage;
  1379.                         while (true) {
  1380.                             if (rCode = PrError() || CheckCancel()) break;
  1381.                             if (p->reverseOrder) {
  1382.                                 if (pageNum < FirstPage) break;
  1383.                             } else {
  1384.                                 if (pageNum > LastPage) break;
  1385.                             };
  1386.                             PrOpenPage(port, nil);
  1387.                             if (!(rCode = PrError())) {
  1388.                                 SetPort((GrafPtr)port);
  1389.                                 ClipRect(&PrintBox);
  1390.                                 if ((**theList).refCon) {
  1391.                                     Print1(theList, p, pageNum);
  1392.                                 } else {
  1393.                                     Print0(theList, p, pageNum);
  1394.                                 };
  1395.                             };
  1396.                             PrClosePage(port);
  1397.                             if (p->reverseOrder) {
  1398.                                 pageNum--;
  1399.                             } else {
  1400.                                 pageNum++;
  1401.                             };
  1402.                         };
  1403.                         PrCloseDoc(port);
  1404.                         if (!(rCode = PrError())) {
  1405.                             if ((**p->hPrint).prJob.bJDocLoop == bSpoolLoop) {
  1406.                                 PrPicFile(p->hPrint, nil, nil, nil, &prStatus);
  1407.                                 rCode = PrError();
  1408.                             };
  1409.                         };
  1410.                     };
  1411.                 };
  1412.             };
  1413.             if ((**theList).refCon) {
  1414.                 DisposHandle((Handle)Breaks1);
  1415.             } else {
  1416.                 DisposHandle((Handle)Breaks0);
  1417.             };
  1418.             DisposDialog(dlog);
  1419.             InitCursor();
  1420.         };
  1421.     };
  1422.     
  1423.     SetPort(savedPort);
  1424.     return PrError();
  1425. }
  1426.  
  1427. /*______________________________________________________________________
  1428.  
  1429.     DrawList - Draw List Manager Dialog User Item.
  1430.     
  1431.     Entry:    theWindow = pointer to page setup dialog.
  1432.                 itemNo = item number.
  1433. _____________________________________________________________________*/
  1434.  
  1435.  
  1436. static pascal void DrawList (WindowPtr theWindow, short itemNo)
  1437.  
  1438. {
  1439.     short            itemType;            /* item type */
  1440.     Handle        item;                    /* item handle */
  1441.     Rect            box;                    /* item rectangle */
  1442.  
  1443.     GetDItem(theWindow, itemNo, &itemType, &item, &box);
  1444.     FrameRect(&box);
  1445.     if (itemNo == FirstItem+fontListItem) {
  1446.         LUpdate((**FontList).port->visRgn, FontList);
  1447.     } else {
  1448.         LUpdate((**SizeList).port->visRgn, SizeList);
  1449.     };
  1450. }
  1451.  
  1452. /*______________________________________________________________________
  1453.  
  1454.     BuildSizeList - Build Font Size List.
  1455.     
  1456.     Entry:        theDialog = pointer to dialog.
  1457. _____________________________________________________________________*/
  1458.  
  1459.  
  1460. static void BuildSizeList (DialogPtr theDialog)
  1461.  
  1462. {
  1463.     short            itemType;        /* item type */
  1464.     Handle        item;                /* item handle */
  1465.     Rect            box;                /* item rectangle */
  1466.     Cell            cell;                /* List Manager cell */
  1467.     short            len;                /* length of font name */
  1468.     Str255        str;                /* multi-purpose string */
  1469.     Str255        str1;                /* current size from size TE box */
  1470.     short            fontNum;            /* font number */
  1471.     short            i;                    /* loop index */
  1472.  
  1473.     LDoDraw(false, SizeList);
  1474.     SetPt(&cell, 0, 0);
  1475.     LGetSelect(true, &cell, FontList);
  1476.     len = 255;
  1477.     LGetCell(str+1, &len, cell, FontList);
  1478.     *str = len;
  1479.     GetFNum(str, &fontNum);
  1480.     LDelRow(0, 0, SizeList);
  1481.     SetPt(&cell, 0, 0);
  1482.     GetDItem(theDialog, FirstItem+sizeTEItem, &itemType, &item, &box);
  1483.     GetIText(item, str1);
  1484.     for (i = PBlock->minFontSize; i <= PBlock->maxFontSize; i++) {
  1485.         if (RealFont(fontNum, i)) {
  1486.             LAddRow(1, cell.v, SizeList);
  1487.             NumToString(i, str);
  1488.             LSetCell(str+1, *str, cell, SizeList);
  1489.             if (EqualString(str, str1, false, false)) 
  1490.                 LSetSelect(true, cell, SizeList);
  1491.             cell.v++;
  1492.         };
  1493.     };
  1494.     LDoDraw(true,SizeList);
  1495.     if (((WindowPeek)theDialog)->visible) {
  1496.         box = (**SizeList).rView;
  1497.         EraseRect(&box);
  1498.         box.right += 15;
  1499.         InvalRect(&box);
  1500.     };
  1501. }
  1502.  
  1503. /*______________________________________________________________________
  1504.  
  1505.     MyFltrProc - Filter proc for custom page setup dialog.
  1506.     
  1507.     Entry:    theDialog = pointer to dialog.
  1508.                 theEvent = pointer to event record.
  1509.                 itemHit = pointer to item number.
  1510.                 
  1511.     This filter proc validates key presses when one of our extra textedit
  1512.     fields is active.
  1513.     
  1514.     For the font size field, we permit at most 2 digits.
  1515.     
  1516.     For the margin fields, we permit at most 6 characters, consisting
  1517.     of digits and at most one decimal point.
  1518. _____________________________________________________________________*/
  1519.  
  1520.  
  1521. static pascal Boolean MyFltrProc (DialogPtr theDialog, EventRecord *theEvent,
  1522.     short *itemHit)
  1523.     
  1524. {
  1525.     short                key;                /* ascii code of key pressed */
  1526.     short                item;                /* item number of current textedit field */
  1527.     TEHandle            textH;            /* handle to TextEdit record */
  1528.     short                selStart;        /* start of selection range */
  1529.     short                selEnd;            /* end of selection range */
  1530.     short                selSize;            /* size of selected part of item */
  1531.     short                oldSize;            /* old text length */
  1532.     short                newSize;            /* new size of field */
  1533.     Boolean            isdig;            /* true if key is a digit */
  1534.     char                *p;                /* pointer into text */
  1535.     char                *pStart;            /* pointer to beginning of text */
  1536.     char                *pEnd;            /* pointer to end of text */
  1537.     short                pIndex;            /* index in text of decimal point */
  1538.  
  1539.     if (theEvent->what == keyDown || theEvent->what == autoKey) {
  1540.         key = theEvent->message & charCodeMask;
  1541.         if (key != returnKey && key != enterKey && key != deleteKey &&
  1542.             key != tabKey && key != leftArrow && key != rightArrow) {
  1543.             item = ((DialogPeek)theDialog)->editField + 1;
  1544.             if (item > FirstItem) {
  1545.                 item -= FirstItem;
  1546.                 textH = ((DialogPeek)theDialog)->textH;
  1547.                 selStart = (**textH).selStart;
  1548.                 selEnd = (**textH).selEnd;
  1549.                 selSize = selEnd - selStart;
  1550.                 oldSize = (**textH).teLength;
  1551.                 newSize = oldSize + 1 - selSize;
  1552.                 isdig = isdigit(key);
  1553.                 if (item == sizeTEItem) {
  1554.                     if (isdig && newSize <= 2) return false;
  1555.                 } else {
  1556.                     if (newSize <= 6) {
  1557.                         if (isdig) return false;
  1558.                         if (key == '.') {
  1559.                             pStart = p = *(**textH).hText;
  1560.                             pEnd = p + oldSize;
  1561.                             while (p < pEnd && *p != '.') p++;
  1562.                             if (p == pEnd) return false;
  1563.                             pIndex = p - pStart;
  1564.                             if (pIndex >= selStart && pIndex < selEnd) return false;
  1565.                         };
  1566.                     };
  1567.                 };
  1568.                 SysBeep(10);
  1569.                 theEvent->what = nullEvent;
  1570.                 return false;
  1571.             };
  1572.         };
  1573.     };
  1574.     if (StdFltrProc) {
  1575.         return (*StdFltrProc)(theDialog, theEvent, itemHit);
  1576.     } else {
  1577.         return false;
  1578.     };
  1579. }
  1580.  
  1581. /*______________________________________________________________________
  1582.  
  1583.     MyItemProc - Handle custom page setup item hit.
  1584.     
  1585.     Entry:    hPrint = handle to print record.
  1586.     
  1587.     Exit:        function result = pointer to print dialog stream object.
  1588. _____________________________________________________________________*/
  1589.  
  1590.  
  1591. static pascal void MyItemProc (DialogPtr theDialog, short itemNo)
  1592.  
  1593. {
  1594.     short                itemType;        /* item type */
  1595.     Handle            item;                /* item handle */
  1596.     Rect                box;                /* item rectangle */
  1597.     Str255            str;                /* multi-purpose string */
  1598.     Str255            str1;                /* second string */
  1599.     unsigned char    *pstr;            /* pointer to cur pos in string */
  1600.     unsigned char    lstr;                /* length of string */
  1601.     long                val;                /* value of string */
  1602.     short                i;                    /* loop index */
  1603.     short                whole;            /* whole part of decimal number */
  1604.     short                frac;                /* fraction part of decimal number */
  1605.     unsigned char    *point;            /* pointer to decimal point in string */
  1606.     short                margin;            /* margin value in 1/100 inches */
  1607.     Point                where;            /* location of mouse click */
  1608.     Cell                cell;                /*    old selected List Manager cell */
  1609.     Cell                newCell;            /* new selected List Manager cell */
  1610.     short                len;                /* length of selected font name */
  1611.     short                fontNum;            /* font number */
  1612.     short                fontSize;        /* font size */
  1613.     short                topMargin;        /* top margin */
  1614.     short                botMargin;        /* bottom margin */
  1615.     short                leftMargin;        /* left margin */
  1616.     short                rightMargin;    /* right margin */
  1617.     
  1618.     if (itemNo > FirstItem) {
  1619.     
  1620.         /* Process a hit on one of our extra dialog items. */
  1621.     
  1622.         GetDItem(theDialog, itemNo, &itemType, &item, &box);
  1623.         switch (itemNo - FirstItem) {
  1624.             case reverseItem:
  1625.                 SetCtlValue((ControlHandle)item, 1 - GetCtlValue((ControlHandle)item));
  1626.                 break;
  1627.             case fontListItem:
  1628.                 SetPort(theDialog);
  1629.                 SetPt(&cell, 0, 0);
  1630.                 LGetSelect(true, &cell, FontList);
  1631.                 GetMouse(&where);
  1632.                 LClick(where, 0, FontList);
  1633.                 SetPt(&newCell, 0, 0);
  1634.                 if (LGetSelect(true, &newCell, FontList)) {
  1635.                     if (cell.v != newCell.v) BuildSizeList(theDialog);
  1636.                 } else {
  1637.                     LSetSelect(true, cell, FontList);
  1638.                 };
  1639.                 break;
  1640.             case sizeListItem:
  1641.                 SetPort(theDialog);
  1642.                 GetMouse(&where);
  1643.                 LClick(where, 0, SizeList);
  1644.                 SetPt(&cell, 0, 0);
  1645.                 if (LGetSelect(true, &cell, SizeList)) {
  1646.                     len = 255;
  1647.                     LGetCell(str+1, &len, cell, SizeList);
  1648.                     *str = len;
  1649.                     GetDItem(theDialog, FirstItem+sizeTEItem, &itemType,
  1650.                         &item, &box);
  1651.                     SetIText(item, str);
  1652.                     SelIText(theDialog, FirstItem+sizeTEItem, 0, 32767);
  1653.                 };
  1654.                 break;
  1655.         };
  1656.         
  1657.     } else {
  1658.     
  1659.         /* Process a hit on the standard OK button. */
  1660.     
  1661.         if (itemNo == ok) {
  1662.         
  1663.             /* Fetch the font. */
  1664.             
  1665.             SetPt(&cell, 0, 0);
  1666.             LGetSelect(true, &cell, FontList);
  1667.             len = 255;
  1668.             LGetCell(str+1, &len, cell, FontList);
  1669.             *str = len;
  1670.             GetFNum(str, &fontNum);
  1671.                 
  1672.             /* Fetch and validate the font size. */
  1673.         
  1674.             GetDItem(theDialog, FirstItem+sizeTEItem, &itemType, 
  1675.                 &item, &box);
  1676.             GetIText(item, str);
  1677.             StringToNum(str, &val);
  1678.             if (val < PBlock->minFontSize || val > PBlock->maxFontSize) {
  1679.                 NumToString(PBlock->minFontSize, str);
  1680.                 NumToString(PBlock->maxFontSize, str1);
  1681.                 ParamText(str, str1, nil, nil);
  1682.                 utl_StopAlert(PBlock->sizeRangeID, nil, 0);
  1683.                 SelIText(theDialog, FirstItem+sizeTEItem, 0, 32767);
  1684.                 return;
  1685.             };
  1686.             fontSize = val; 
  1687.         
  1688.             /* Fetch and evaluate the four margins. */
  1689.             
  1690.             for (i = 0; i < 4; i++) {
  1691.                 GetDItem(theDialog, FirstItem+leftTEItem+i, &itemType, 
  1692.                     &item, &box);
  1693.                 GetIText(item, str);
  1694.                 pstr = str+1;
  1695.                 lstr = *str;
  1696.                 while (lstr) {
  1697.                     if (*pstr == '.') break;
  1698.                     pstr++;
  1699.                     lstr--;
  1700.                 };
  1701.                 *str1 = pstr-str-1;
  1702.                 memcpy(str1+1, str+1, *str1);
  1703.                 StringToNum(str1, &val);
  1704.                 whole = val;
  1705.                 frac = 0;
  1706.                 if (lstr) {
  1707.                     point = pstr;
  1708.                     pstr++;
  1709.                     lstr--;
  1710.                     *str1 = 2;
  1711.                     *(str1+1) = '0';
  1712.                     *(str1+2) = '0';
  1713.                     if (lstr) {
  1714.                         *(str1+1) = *(point+1);
  1715.                         if (lstr > 1) *(str1+2) = *(point+2);
  1716.                     };
  1717.                     StringToNum(str1, &val);
  1718.                     frac = val;
  1719.                 };
  1720.                 margin = 100*whole + frac;
  1721.                 switch (i) {
  1722.                     case 0: leftMargin = margin; break;
  1723.                     case 1: rightMargin = margin; break;
  1724.                     case 2: topMargin = margin; break;
  1725.                     case 3: botMargin = margin; break;
  1726.                 };
  1727.             };
  1728.             
  1729.             /* Check for margins too big.  We require at least 4 inches
  1730.                 of printing area both horizontally and vertically. */
  1731.             
  1732.             CalcPrintBox(PBlock->hPrint, leftMargin, rightMargin, topMargin, botMargin);
  1733.             if (PrintBox.right - PrintBox.left < 
  1734.                 4*(**PBlock->hPrint).prInfo.iHRes) {
  1735.                 utl_StopAlert(PBlock->marginsTooBigID, nil, 0);
  1736.                 SelIText(theDialog, FirstItem+leftTEItem, 0, 32767);
  1737.                 return;
  1738.             } else if (PrintBox.bottom - PrintBox.top < 
  1739.                 4*(**PBlock->hPrint).prInfo.iVRes) {
  1740.                 utl_StopAlert(PBlock->marginsTooBigID, nil, 0);
  1741.                 SelIText(theDialog, FirstItem+topTEItem, 0, 32767);
  1742.                 return;
  1743.             };
  1744.         
  1745.             /* Set the new values of the print record fields. */
  1746.             
  1747.             PBlock->fontNum = fontNum;
  1748.             PBlock->fontSize = fontSize;
  1749.             PBlock->topMargin = topMargin;
  1750.             PBlock->botMargin = botMargin;
  1751.             PBlock->leftMargin = leftMargin;
  1752.             PBlock->rightMargin = rightMargin;
  1753.             GetDItem(theDialog, FirstItem+reverseItem, &itemType, &item, &box);
  1754.             PBlock->reverseOrder = GetCtlValue((ControlHandle)item);
  1755.             
  1756.         };
  1757.         
  1758.         /* Call the standard item handler. */
  1759.         
  1760.         (*StdItemProc)(theDialog, itemNo);
  1761.         
  1762.     };
  1763. }
  1764.  
  1765. /*______________________________________________________________________
  1766.  
  1767.     MyStlDlgInit - Initialize custom page setup dialog.
  1768.     
  1769.     Entry:    hPrint = handle to print record.
  1770.     
  1771.     Exit:        function result = pointer to print dialog stream object.
  1772. _____________________________________________________________________*/
  1773.  
  1774.  
  1775. static pascal TPPrDlg MyStlDlgInit (THPrint hPrint)
  1776.  
  1777. {
  1778.     DialogPtr        theDialog;        /* pointer to dialog */
  1779.     short                itemType;        /* item type */
  1780.     Handle            item;                /* item handle */
  1781.     Rect                box;                /* item rectangle */
  1782.     Str255            str;                /* multi-purpose string */
  1783.     Str255            str1;                /* second multi-purpose string */
  1784.     short                i;                    /* loop index */
  1785.     short                val;                /* value */
  1786.     short                whole;            /* whole part of decimal num */
  1787.     short                frac;                /* fraction part of decimal num */
  1788.     unsigned char    len;                /* length of string */
  1789.     Boolean            laser;            /* true if laserwriter */
  1790.     MenuHandle        tempMenu;        /* tempory menu for enumerating fonts */
  1791.     short                numFonts;        /* number of fonts */
  1792.     Rect                dataBounds;        /* dimensions of font list */
  1793.     Point                cSize;            /* font list cell size */
  1794.     Cell                cell;                /* list manager cell */
  1795.     Rect                dlogRect;        /* dialog rectangle */
  1796.     
  1797.     theDialog = (DialogPtr)PrtStlDialog;
  1798.     laser = utl_IsLaser(hPrint);
  1799.     
  1800.     /* Append our extra dialog items. */
  1801.     
  1802.     FirstItem = utl_AppendDITL(theDialog, PBlock->ditlID) - 1;
  1803.     
  1804.     /* Center the dialog. */
  1805.     
  1806.     dlogRect = theDialog->portRect;
  1807.     utl_CenterDlogRect(&dlogRect, PBlock->menuPick);
  1808.     MoveWindow(theDialog, dlogRect.left, dlogRect.top, false);
  1809.     
  1810.     /* Initialize line separator user item. */
  1811.     
  1812.     GetDItem(theDialog, FirstItem+sepLineItem, &itemType, &item, &box);
  1813.     SetDItem(theDialog, FirstItem+sepLineItem, itemType, 
  1814.         (Handle)utl_FrameItem, &box);
  1815.         
  1816.     /* Initialize font list user item.  See TN 191. */
  1817.         
  1818.     GetDItem(theDialog, FirstItem+fontListItem, &itemType, &item, &box);
  1819.     SetDItem(theDialog, FirstItem+fontListItem, itemType, 
  1820.         (Handle)DrawList, &box);
  1821.     GetFontName(PBlock->fontNum, str);
  1822.     if (!*str) GetFontName(applFont, str);
  1823.     tempMenu = NewMenu(9999, "\px");
  1824.     AddResMenu(tempMenu, 'FONT');
  1825.     numFonts = CountMItems(tempMenu);
  1826.     InsetRect(&box, 1, 1);
  1827.     box.right -= 15;
  1828.     SetRect(&dataBounds, 0, 0, 1, numFonts);
  1829.     SetPt(&cSize, 0, 0);
  1830.     FontList = LNew(&box, &dataBounds, cSize, 0, theDialog, false, false,
  1831.         false, true);
  1832.     LDoDraw(false, FontList);
  1833.     (**FontList).selFlags = lOnlyOne;
  1834.     SetPt(&cell, 0, 0);
  1835.     for (i = 1; i <= numFonts; i++) {
  1836.         GetItem(tempMenu, i, str1);
  1837.         LSetCell(str1+1, *str1, cell, FontList);
  1838.         if (EqualString(str, str1, false, false)) {
  1839.             LSetSelect(true, cell, FontList);
  1840.             LAutoScroll(FontList);
  1841.         };
  1842.         cell.v++;
  1843.     };
  1844.     DisposeMenu(tempMenu);
  1845.     LDoDraw(true, FontList);
  1846.         
  1847.     /* Initialize size text edit item. */
  1848.     
  1849.     GetDItem(theDialog, FirstItem+sizeTEItem, &itemType, &item, &box);
  1850.     NumToString(PBlock->fontSize, str);
  1851.     SetIText(item, str);
  1852.     
  1853.     /* Initialize font size list user item. */
  1854.     
  1855.     GetDItem(theDialog, FirstItem+sizeListItem, &itemType, &item, &box);
  1856.     SetDItem(theDialog, FirstItem+sizeListItem, itemType,
  1857.         (Handle)DrawList, &box);
  1858.     InsetRect(&box, 1, 1);
  1859.     box.right -= 15;
  1860.     SetRect(&dataBounds, 0, 0, 1, 0);
  1861.     SetPt(&cSize, 0, 0);
  1862.     SizeList = LNew(&box, &dataBounds, cSize, 0, theDialog, false, false,
  1863.         false, true);
  1864.     (**SizeList).selFlags = lOnlyOne;
  1865.     BuildSizeList(theDialog);
  1866.         
  1867.     /* Initialize reverse order checkbox. */
  1868.     
  1869.     GetDItem(theDialog, FirstItem+reverseItem, &itemType, &item, &box);
  1870.     SetCtlValue((ControlHandle)item, PBlock->reverseOrder);
  1871.     
  1872.     /* Initialize margin text edit items. */
  1873.     
  1874.     for (i = 0; i < 4; i++) {
  1875.         switch (i) {
  1876.             case 0: val = PBlock->leftMargin; break;
  1877.             case 1: val = PBlock->rightMargin; break;
  1878.             case 2: val = PBlock->topMargin; break;
  1879.             case 3: val = PBlock->botMargin; break;
  1880.         };
  1881.         whole = val/100;
  1882.         frac = val%100;
  1883.         NumToString(whole, str);
  1884.         NumToString(frac, str1);
  1885.         if (*str1 == 1) {
  1886.             *str1 = 2;
  1887.             *(str1+2) = *(str1+1);
  1888.             *(str1+1) = '0';
  1889.         };
  1890.         len = *str;
  1891.         *(str+len+1) = '.';
  1892.         memcpy(str+len+2, str1+1, *str1);
  1893.         *str += *str1 + 1;
  1894.         GetDItem(theDialog, FirstItem+leftTEItem+i, &itemType, &item, &box);
  1895.         SetIText(item, str);
  1896.     };
  1897.     
  1898.     /* Save standard item handler and filterproc addresses, and patch in the addresses
  1899.         of our item handler and filterproc. */ 
  1900.         
  1901.     StdItemProc = PrtStlDialog->pItemProc;
  1902.     StdFltrProc = PrtStlDialog->pFltrProc;
  1903.     PrtStlDialog->pItemProc = MyItemProc;
  1904.     PrtStlDialog->pFltrProc = MyFltrProc;
  1905.     
  1906.     /* Return. */
  1907.         
  1908.     return PrtStlDialog;
  1909. }
  1910.  
  1911. /*______________________________________________________________________
  1912.  
  1913.     rpp_StlDlog - Present Customized Page Setup Dialog.
  1914.     
  1915.     Entry:    p = pointer to parameter block, with fields set as follows:
  1916.     
  1917.                 hPrint = handle to print record.
  1918.                 fontNum = font number.
  1919.                 fontSize = font size.
  1920.                 topMargin = top margin, in 1/100 inch.
  1921.                 botMargin = bottom margin, in 1/100 inch.
  1922.                 leftMargin = left margin, in 1/100 inch.
  1923.                 rightMargin = right margin, in 1/100 inch.
  1924.                 reverseOrder = true if pages to be printed in reverse order.
  1925.                 ditlID = resource id of DITL to be appended to standard
  1926.                     page setup dialog.
  1927.                 sizeRangeID = resource id of font size range error alert.
  1928.                 marginsTooBigID = page margins too big alert.
  1929.                 minFontSize = min legal font size.
  1930.                 maxFontSize = max legal font size.
  1931.                 menuPick = true if Page Setup command was via menu pick, 
  1932.                     false if command key used.
  1933.                     
  1934.     Exit:        function result = true if OK button clicked, 
  1935.                     false if Cancel button clicked.
  1936.                     
  1937.                 Following fields are updated in parameter block if the OK button
  1938.                 was clicked:
  1939.                     
  1940.                 fontNum = font number.
  1941.                 fontSize = font size.
  1942.                 topMargin = top margin, in 1/100 inch.
  1943.                 botMargin = bottom margin, in 1/100 inch.
  1944.                 leftMargin = left margin, in 1/100 inch.
  1945.                 rightMargin = right margin, in 1/100 inch.
  1946.                 reverseOrder = true if pages to be printed in reverse order.
  1947. _____________________________________________________________________*/
  1948.  
  1949.  
  1950. Boolean rpp_StlDlog (rpp_PrtBlock *p)
  1951.  
  1952. {
  1953.     Boolean         okClicked;                /* true if OK clicked */
  1954.  
  1955.     PBlock = p;
  1956.     FontList = nil;
  1957.     SizeList = nil;
  1958.     PrtStlDialog = PrStlInit(p->hPrint);
  1959.     okClicked = PrDlgMain(p->hPrint, MyStlDlgInit);
  1960.     if (FontList) {
  1961.         (**FontList).vScroll = nil;
  1962.         LDispose(FontList);
  1963.     };
  1964.     if (SizeList) {
  1965.         (**SizeList).vScroll = nil;
  1966.         LDispose(SizeList);
  1967.     };
  1968.     return okClicked;
  1969. }
  1970.